//
//  SEWorld.cpp
//  Space Explorer
//
//  Created by Yann Blaudin de Thé on 14/04/13.
//  Copyright (c) 2013 TeaTime. All rights reserved.
//

#include "SEWorld.h"


SEWorld::SEWorld(irr::IEventReceiver* _irr_receiver) : _light(NULL), _sun(NULL), _clock(SEClock()), _cam_ph_pos(vec3d(0.0f, 0.0f, 0.0f)), _t_wrap(1.0f) {
    irr::video::E_DRIVER_TYPE driverType = irr::video::EDT_OPENGL;
    
    _irr_device = irr::createDevice(driverType, irr::core::dimension2d<irr::u32>(1600, 1200), 16, false, false, false, _irr_receiver);
    
	if (_irr_device == 0)
		std::cerr << "Erreur a l'initialisation du device Irrlicht" << std::endl;
    
    _irr_driver = _irr_device->getVideoDriver();
    _irr_smgr = _irr_device->getSceneManager();
    _irr_guienv = _irr_device->getGUIEnvironment();
    
//    // Initialize bullet
//	_BroadPhase = new btAxisSweep3(btVector3(-1000, -1000, -1000), btVector3(1000, 1000, 1000));
//	_CollisionConfiguration = new btDefaultCollisionConfiguration();
//	_Dispatcher = new btCollisionDispatcher(_CollisionConfiguration);
//	_Solver = new btSequentialImpulseConstraintSolver();
//	_btWorld = new btDiscreteDynamicsWorld(_Dispatcher, _BroadPhase, _Solver, _CollisionConfiguration);
    
    _irr_cam = _irr_smgr->addCameraSceneNodeFPS(0, 100.0f, 50.0f);
//    _irr_cam = _irr_smgr->addCameraSceneNode();
//    _irr_cam->setPosition(vec3f(0.0f, 0.0f, 0.0f));
    _irr_cam->bindTargetAndRotation(true);
    _irr_cam->setFarValue(10000000.0f);
    
    // Réglage de la FOV d'après ce post
    // http://orbiter.dansteph.com/forum/read.php?f=3&i=56601&t=56601
    _irr_cam->setFOV(40.*M_PI/180.0f);
    
    _irr_device->setWindowCaption(L"Space Explorer 2013");
    _irr_device->getCursorControl()->setVisible(false);
    
    _clock.setToPresentTime();
    _clock.tic();
    
    SESpice::Init(GetApplicationResourcesPath() + "KernelsToLoad.ker");
    
    _lastFPS = -1;
    
    _cockpit = new SECockpit(_irr_device);
    
}

SEWorld::~SEWorld() {
    _irr_device->drop();
    
    SESpice::Clear(GetApplicationResourcesPath() + "KernelsToLoad.ker");
    
    std::vector<SEPlanet*>::iterator planet_iterator;
    
    for(planet_iterator = _planets.begin();
        planet_iterator != _planets.end();
        planet_iterator++) {
        delete *planet_iterator;
    }
    
    std::vector<SEVessel*>::iterator vessel_iterator;
    
    for(vessel_iterator = _vessels.begin();
        vessel_iterator != _vessels.end();
        vessel_iterator++) {
        delete *vessel_iterator;
    }
    
    delete _cockpit;
    
//  delete _BroadPhase;
//	delete _CollisionConfiguration;
//	delete _Dispatcher;
//	delete _Solver;
//	delete _btWorld;
    
}

void SEWorld::loadBSC(const std::string& filename) {
    std::ifstream bsc(filename.c_str());
    
    irr::f32 mag, col1, col2, ra, dec;
    irr::f32 x, y, z, far;
    
    irr::f32 screenW = _irr_driver->getScreenSize().Width;
    irr::f32 screenH = _irr_driver->getScreenSize().Height;

    far = _irr_cam->getFarValue()*0.8f;
//    far = _irr_cam->getFarValue()*cos(screenH/screenW*_irr_cam->getFOV()*M_PI/180)*0.9f;
    
    std::string bill_path = GetApplicationResourcesPath() + "particlewhite.bmp";
    irr::video::ITexture* bill_tex = _irr_driver->getTexture(bill_path.c_str());
    
    int nb_star = 0;
    while(bsc) {
        bsc >> col1 >> col2 >> ra >> dec >> mag;
        
        if (mag > 0.995f) {
            x = far*sin(ra)*cos(dec);
            y = far*cos(ra)*cos(dec);
            z = far*sin(dec);
            
            nb_star++;
            
            irr::f32 size = 1.8e-3*far*mag;
            irr::scene::IBillboardSceneNode* bill = _irr_smgr->addBillboardSceneNode(NULL,
                                                     irr::core::dimension2d<irr::f32>(size, size),
                                                     vec3f(x,y,z),
                                                     -1);
            bill->setMaterialFlag(irr::video::EMF_LIGHTING, false);
            bill->setMaterialTexture(0, bill_tex);
            
        }
        
    }
    
    std::cout << nb_star << " etoiles importees" << std::endl;
    
}

irr::IrrlichtDevice* SEWorld::getIrrDevice() {
    return _irr_device;
}

irr::scene::ISceneManager* SEWorld::getIrrSceneManager() {
    return _irr_smgr;
}

SEPlanet* SEWorld::createPlanet(SEPlanet* attractor, const irr::core::stringw& disp_name, const std::string& spice_name, const std::string& ground_tex, const std::string& cloud_tex, const std::string& normal_tex) {
    
    std::cout << std::endl;
    std::cout << "===============================" << std::endl;
    std::cout << "  Creation de " << spice_name << std::endl;
    std::cout << "===============================" << std::endl;
    
    SEPlanet *planet = new SEPlanet(_irr_device, attractor, disp_name, spice_name, _irr_driver->getTexture(ground_tex.c_str()), _irr_driver->getTexture(cloud_tex.c_str()), _irr_driver->getTexture(normal_tex.c_str()));
    
    planet->update(_clock, _cam_ph_pos);

    _planets.push_back(planet);
    
    return planet;
    
}

SEVessel* SEWorld::createVessel(const irr::core::stringw& disp_name, const std::string& mesh_file) {
    irr::scene::IAnimatedMesh* mesh = _irr_smgr->getMesh(mesh_file.c_str());
    
    SEVessel *vessel = new SEVessel(_irr_device, disp_name, mesh);
    
    vessel->update(_clock, _cam_ph_pos);
    
    _vessels.push_back(vessel);
    
    return vessel;
    
}

irr::scene::ILightSceneNode* SEWorld::createLight(SEPlanet* body) {
    if (_light) {
        std::cout << "La lumiere a deja ete cree." << std::endl;
        return _light;
    }
    
    _sun = body;
    _sun->getIrrNode()->setVisible(false);
    
    _light =
    _irr_smgr->addLightSceneNode(0,
                                 vec3f(),
                                 irr::video::SColorf(1.0f, 1.0f, 1.0f),
                                 10000000000.0f);
    
//    irr::f32 size = _irr_cam->getFarValue()/10;;
//    irr::scene::IBillboardSceneNode* bill =
//    _irr_smgr->addBillboardSceneNode(_light, irr::core::dimension2d<irr::f32>(size, size));
//    
//    bill->setMaterialFlag(irr::video::EMF_LIGHTING, false);
//    bill->setMaterialFlag(irr::video::EMF_ZWRITE_ENABLE, false);
//    bill->setMaterialType(irr::video::EMT_TRANSPARENT_ADD_COLOR);
//    bill->setMaterialTexture(0, _irr_driver->getTexture((GetApplicationResourcesPath() + "particlewhite.bmp").c_str()));
    
    return _light;
    
}

irr::scene::ILightSceneNode* SEWorld::getLight() {
    return _light;
}

SECockpit* SEWorld::getCockpit() {
    return _cockpit;
}

std::vector<SEPlanet*>& SEWorld::getPlanets() {
    return _planets;
}

std::vector<SEVessel*>& SEWorld::getVessels() {
    return _vessels;
}

btVector3 SEWorld::getGravite(const btVector3& position) {
    std::vector<SEPlanet*>::iterator planet_iterator;
    vec3d pos;
    SpiceDouble gp;
    btVector3 ray, gravite(0., 0., 0.);
    double dist;
    
    for (planet_iterator = _planets.begin();
         planet_iterator != _planets.end();
         planet_iterator++) {
        gp = (*planet_iterator)->getGravitationalParameter();
        pos = (*planet_iterator)->getPosition();
        
        ray = btVector3(pos.X-position.x(), pos.Y-position.y(), pos.Z-position.z());
        dist = ray.length();
//        std::cout << "dist : " << dist << std::endl;
        gravite += gp/pow(dist,3)*ray;
        
    }
    
    return gravite;    
    
}

irr::scene::ICameraSceneNode* SEWorld::getIrrCamera() {
    return _irr_cam;
}

vec3d SEWorld::getCameraPos() const {
    return _cam_ph_pos;
}

void SEWorld::setCameraPos(const vec3d& pos) {
    _cam_ph_pos = pos;
}

SpiceDouble SEWorld::setWarpCoeff(SpiceDouble coeff) {
    _t_wrap *= coeff;
    _cockpit->setWarp(_t_wrap);
}

bool SEWorld::run() {
    return _irr_device->run();
}

void SEWorld::loop() {
    double dt;
    
    if (_irr_device->isWindowActive())
    {
        _irr_driver->beginScene(true, true, 0);
        
        _irr_smgr->drawAll();
        _irr_guienv->drawAll();
        
        int fps = _irr_driver->getFPS();
        
        dt = _t_wrap*_clock.tic();
        _clock.update(dt);
        
        std::vector<SEPlanet*>::iterator planet_iterator;
        
        for (planet_iterator = _planets.begin();
             planet_iterator != _planets.end();
             planet_iterator++) {
            (*planet_iterator)->update(_clock, _cam_ph_pos);
        }
        
        _light->setPosition(_sun->getIrrPosition());
        
        std::vector<SEVessel*>::iterator vessel_iterator;
        
        for (vessel_iterator = _vessels.begin();
             vessel_iterator != _vessels.end();
             vessel_iterator++) {
            (*vessel_iterator)->update(_clock, _cam_ph_pos);
            
        }
        
        _cockpit->setTime(_clock);
        
        if (_lastFPS != fps)
        {
            _cockpit->setFPS(fps);
            _lastFPS = fps;
        }
        
        // We're all done drawing, so end the scene.
        _irr_driver->endScene();
        
    }
}


